// UPD 服务端
#include <iostream>
#include <string>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <utility>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unordered_map>
#include <queue>
#include "log.hpp"
class UDPServer
{
public:
    UDPServer(uint16_t port, std::string ip = "") : _port(port), _ip(ip)
    {
    }

    bool initServer()
    {
        // 1. 创建套接字 返回值  套接字的文件描述符
        _socketfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_socketfd < 0)
        {
            LogMessage(FATAL, "%d,%s", errno, strerror(errno));
            exit(-1);
        }
        // 2. bind: 将ip和port在内核中和我们当前的进程强关联
        //  int bind(int sockfd, const struct sockaddr *addr,
        //         socklen_t addrlen);
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        // 支持任意ip访问
        local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());

        int bind_ret = bind(_socketfd, (struct sockaddr *)&local, sizeof(local));
        if (bind_ret < 0)
        {
            LogMessage(FATAL, "%d,%s", errno, strerror(errno));
            exit(-2);
        }

        // success
        LogMessage(NORMAL, "server init success...");
        return true;
    }
    void start()
    {
        // 启动服务
        // 常驻进程，永不退出
        char buffer[1024];
        while (1)
        {

            // peer 纯输出型参数
            struct sockaddr_in peer;
            memset(&peer, 0, sizeof(peer));
            memset(buffer, 0, sizeof(buffer));
            // peer是缓冲区的大小
            // len实际读到的大小
            socklen_t len = sizeof(peer);

            // 从套接字中读取数据
            // ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
            //             struct sockaddr *src_addr, socklen_t *addrlen);

            char key[64] = {0};
            //从客户端读取数据
            ssize_t read_size = recvfrom(_socketfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);
            if (read_size > 0)
            {
                buffer[read_size] = 0;
                uint16_t c_port = ntohs(peer.sin_port);
                std::string c_ip = inet_ntoa(peer.sin_addr);
                // 将ip和端口 格式化输出到u_map的key中
                snprintf(key, sizeof(key), "%s:%u", c_ip.c_str(), c_port);
                //LogMessage(NORMAL, "key:%s", key);
                auto it = _user.find(key);
                if (it == _user.end())
                {
                    //LogMessage(NORMAL, "add new user: %s", key);
                    _user.insert({key, peer});
                }
            }
            for (auto &it : _user)
            {
                std::string send_message = key;
                send_message += '#';
                send_message += buffer;
                LogMessage(NORMAL, "push to message: %s : %s", it.first.c_str(),send_message.c_str());
                //向客户端发送数据
                sendto(_socketfd, send_message.c_str(), send_message.size(), 0, (struct sockaddr *)&(it.second), sizeof(it.second));
            }
        }
    }

    ~UDPServer()
    {
        if (_socketfd > 0)
        {
            close(_socketfd);
        }
    }

private:
    std::string _ip;
    uint16_t _port;
    int _socketfd;

    std::unordered_map<std::string, struct sockaddr_in> _user;
    std::queue<std::string> _message_queue;
};